<!--
文件预览
@author luguoxiang
@Date: 2024/03/22 16:55
开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
-->
<template>
  <div :id="id" class="lg-file-viewer-view" @wheel="changeScale">
    <lg-empty :data="files" class="lg-file-preview-box">
      <audio v-if="type === 0" :src="url" controls />
      <div
        v-else-if="type === 1"
        class="lg-file-viewer-transform"
        @mousedown.prevent="dragstart"
        @mousemove.prevent="mousemove"
        @mouseup.prevent="dragend"
      >
        <div :style="{ transform: `translate(${translateX}px, ${translateY}px)` }">
          <img
            :src="url"
            :style="{ transform: `scale(${scale}) rotate(${rotate}deg) scaleX(${scaleX}) scaleY(${scaleY})` }"
          />
        </div>
      </div>
      <div
        v-else-if="type === 2"
        class="lg-file-viewer-transform"
        @mousedown.prevent="dragstart"
        @mousemove.prevent="mousemove"
        @mouseup.prevent="dragend"
      >
        <div :style="{ transform: `translate(${translateX}px, ${translateY}px)` }">
          <video
            :src="url"
            controls
            :style="{ transform: `scale(${scale}) rotate(${rotate}deg) scaleX(${scaleX}) scaleY(${scaleY})` }"
          />
        </div>
      </div>
      <iframe v-else-if="type === 3" :src="url" style="width: 900px" class="lg-file-viewer-iframe" />
      <iframe v-else-if="type === 4" :src="url" class="lg-file-viewer-iframe" />
      <div v-else style="padding: 32px; background-color: #fff">
        暂不支持该类型附件<template v-if="name">【{{ name }}】</template>预览功能，请
        <a class="gl-link" @click="download">下载</a>
        查看
      </div>
    </lg-empty>
    <template v-if="!hideCtrl">
      <div v-drag class="lg-file-viewer-ctrl">
        <template v-if="type === 1 || type === 2">
          <div class="lg-file-viewer-btn" title="上下镜像" @click="mirrorY">
            <mirror-icon style="transform: rotate(90deg)" />
          </div>
          <div class="lg-file-viewer-btn" title="左右镜像" @click="mirrorX">
            <mirror-icon />
          </div>
          <div class="lg-file-viewer-btn" title="旋转" @click="rotation">
            <rotation-icon />
          </div>
        </template>
        <template v-if="type === 1 || type === 2 || type === 3">
          <div class="lg-file-viewer-btn" title="缩小" @click="zoomOut">
            <zoom-out-icon />
          </div>
          <div class="lg-file-viewer-size" @click="swap">
            <template v-if="type === 3">{{ scale }}px</template>
            <template v-else>{{ round(scale * 100, 0) }}%</template>
          </div>
          <div class="lg-file-viewer-btn" title="放大" @click="zoomIn">
            <zoom-in-icon />
          </div>
          <div class="lg-file-viewer-btn" title="还原" @click="revert">
            <rectangle-icon />
          </div>
        </template>
        <div class="lg-file-viewer-btn" :class="{ 'inner-disabled': innerIndex === 0 }" title="上一个" @click="prev()">
          <chevron-left-icon />
        </div>
        <div
          class="lg-file-viewer-btn"
          :class="{ 'inner-disabled': innerIndex === files.length - 1 }"
          title="下一个"
          @click="next()"
        >
          <chevron-right-icon />
        </div>
        <div class="lg-file-viewer-btn" title="下载" @click="download()">
          <download-icon />
        </div>
      </div>
    </template>
  </div>
</template>

<script>
import {
  ChevronLeftIcon,
  ChevronRightIcon,
  DownloadIcon,
  MirrorIcon,
  RectangleIcon,
  RotationIcon,
  ZoomInIcon,
  ZoomOutIcon,
} from 'tdesign-icons-vue-next';
import LgEmpty from '../LgEmpty/index.vue';
import { round, toValidValue } from '../../utils/math';
import { getFileAccessAuthUrl, nextId } from '@/soar';

const TYPE = {
  // audio 0
  mp3: 0,
  // img: 1
  png: 1,
  jpg: 1,
  jpeg: 1,
  gif: 1,
  bmp: 1,
  // video: 2
  mp4: 2,
  ogg: 2,
  // text: 3
  txt: 3,
  json: 3,
  log: 3,
  java: 3,
  js: 3,
  css: 3,
  xml: 3,
  yaml: 3,
  yml: 3,
  html: 3,
  sh: 3,
  bat: 3,
  sql: 3,
  pdf: 4,
  // word
  doc: 5,
  docx: 5,
  xls: 5,
  xlsx: 5,
  ppt: 5,
  pptx: 5,
};

export default {
  name: 'LgFileViewerView',
  components: {
    LgEmpty,
    ChevronLeftIcon,
    ChevronRightIcon,
    RotationIcon,
    ZoomOutIcon,
    ZoomInIcon,
    DownloadIcon,
    RectangleIcon,
    MirrorIcon,
  },
  props: {
    files: {
      type: Array,
      required: true,
    },
    index: {
      type: Number,
      required: true,
    },
    hideCtrl: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      id: `lgv-${nextId()}`,
      innerIndex: 0,
      type: -1,
      url: '',
      name: '',
      fileId: null,
      scale: 1,
      rotate: 0,
      scaleX: 1,
      scaleY: 1,
      translateX: 0,
      translateY: 0,
    };
  },
  watch: {
    index: {
      handler(v) {
        this.innerIndex = v;
        this.setFile();
      },
      immediate: true,
    },
  },
  methods: {
    round,
    download() {
      const file = { url: this.url, name: this.name };
      const a = document.createElement('a');
      a.href = file.url;
      a.target = '_blank';
      a.download = file.name;
      a.click();
      URL.revokeObjectURL(a.href);
      a.remove();
    },
    dragstart(e) {
      this.clientX = e.clientX;
      this.clientY = e.clientY;
      this.translateX1 = this.translateX;
      this.translateY1 = this.translateY;
      this.clientAble = true;
    },
    mousemove(e) {
      if (this.clientAble) {
        this.translateX = e.clientX - this.clientX + this.translateX1;
        this.translateY = e.clientY - this.clientY + this.translateY1;
      }
    },
    dragend() {
      this.clientAble = false;
    },
    prev() {
      if (this.innerIndex > 0) {
        this.innerIndex -= 1;
      }
      this.setFile();
    },
    next() {
      if (this.innerIndex < this.files.length - 1) {
        this.innerIndex += 1;
      }
      this.setFile();
    },
    mirrorY() {
      this.scaleY = this.scaleY === 1 ? -1 : 1;
    },
    mirrorX() {
      this.scaleX = this.scaleX === 1 ? -1 : 1;
    },
    rotation() {
      this.rotate = toValidValue(this.rotate + 45);
      if (this.rotate > 315) {
        this.rotate = 0;
      }
    },
    zoomOut() {
      if (this.type === 3) {
        this.scale = toValidValue(this.scale - 1);
        this.changeFontSize();
        return;
      }
      this.scale = toValidValue(this.scale - 0.1);
      if (this.scale < 0.1) {
        this.scale = 0.1;
      }
    },
    zoomIn() {
      if (this.type === 3) {
        this.scale = toValidValue(this.scale + 1);
        this.changeFontSize();
        return;
      }
      this.scale = toValidValue(this.scale + 0.1);
    },
    swap() {
      const temp = this.temp ?? (this.type === 3 ? 14 : 1);
      this.temp = this.scale;
      this.scale = temp;
      this.changeFontSize();
    },
    revert() {
      this.scale = this.type === 3 ? 14 : 1;
      this.rotate = 0;
      this.scaleX = 1;
      this.scaleY = 1;
      this.translateX = 0;
      this.translateY = 0;
      this.changeFontSize();
    },
    setFile() {
      const file = this.files[this.innerIndex];
      if (!file) {
        return;
      }
      if (typeof file === 'string') {
        this.name = this.getName(null, file);
        this.url = getFileAccessAuthUrl(file);
        this.fileId = null;
      } else {
        this.name = this.getName(file.name, file.url);
        this.url = getFileAccessAuthUrl(file.url);
        this.fileId = file.id;
      }
      this.type = this.getType(this.name);
      this.$nextTick(this.revert);
    },
    getName(val, url) {
      if (val) {
        return val;
      }
      const names = url.split('?')[0].split('/');
      return names[names.length - 1];
    },
    getType(name) {
      if (name) {
        name = name.split('.');
        if (name.length > 1) {
          name = name[name.length - 1];
          return TYPE[name.toLocaleLowerCase()] ?? -1;
        }
      }
      return -1;
    },
    changeScale(e) {
      if (this.type === 1 || this.type === 2) {
        const delta = e.wheelDelta ? e.wheelDelta : -e.deltaY;
        if (delta > 0) {
          this.zoomIn();
        } else {
          this.zoomOut();
        }
      }
    },
    changeFontSize() {
      if (this.type === 3) {
        const el = document.getElementById(this.id).querySelector('iframe');
        if (el) {
          el.contentDocument.body.style.cssText = `font-size:${this.scale}px`;
        }
      }
    },
  },
};
</script>
<style lang="less" scoped>
.lg-file-viewer-view {
  position: relative;
  height: 100%;
  width: 100%;
  .lg-file-preview-box {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
  }
  .lg-file-viewer-transform {
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .lg-file-viewer-iframe {
    height: 100%;
    width: 100%;
    color: var(--app-color-text-primary);
    background: var(--app-color-bg-primary);
    line-height: 1.5;
  }
  .lg-file-viewer-ctrl {
    width: auto !important;
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    z-index: 10000;
    display: flex;
    justify-content: center;
    align-items: center;
    top: calc(100% - 56px);
    background-color: rgba(#0000007f, 0.5);
    color: var(--app-color-bg-primary);
    font-size: 20px;
    border-radius: var(--app-border-radius);
    .lg-file-viewer-btn {
      cursor: pointer;
      padding: 5px 8px;
    }
    .lg-file-viewer-size {
      font-size: 14px;
      cursor: pointer;
    }
  }
  .inner-disabled {
    cursor: not-allowed !important;
  }
}
</style>
